
import { _decorator, Component, Node, Prefab, Mask, PhysicsSystem, geometry, instantiate, Quat, Vec3, RigidBody } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('BulletScript')
export class BulletScript extends Component {
    public maxDistance: number = 1000000;
    public floatInfrontOfWall: number = 1;
    @property(Prefab)
    public decalHitWall: Prefab = null!;
    @property(Prefab)
    public bloodEffect: Prefab = null!;

    start() {
        let wpos = this.node.getWorldPosition();
        let forward = this.node.forward.clone();
        // 根据子弹节点的世界坐标、前方朝向向量创建一条射线
        let ray = new geometry.Ray(wpos.x, wpos.y, wpos.z, forward.x, forward.y, forward.z);

        // raycastClosest 接口返回一个 boolean 值表示是否检测到碰撞体，并保存与射线起点最近的碰撞体信息到 PhysicsSystem.instance.raycastClosestResult 中
        let isHit = PhysicsSystem.instance.raycastClosest(ray, 0xffffffff, this.maxDistance, true);
        if (isHit) {
            // raycastClosestResult 是射线检测结果对象，包含击中坐标点，目标距离、击中的碰撞体、世界坐标下击中面的法线
            let result = PhysicsSystem.instance.raycastClosestResult;

            // 根据世界坐标下击中面的法线与前方朝向向量生成四元数，用于旋转粒子特效节点
            let quat = new Quat;
            Quat.fromViewUp(quat, new Vec3(result.hitNormal.x, result.hitNormal.y, result.hitNormal.z), new Vec3(0, 1, 0));

            // 判断发生碰撞的组件节点名称，分别处理墙壁和敌人两种情况
            if (result.collider.node.name.indexOf('Wall') >= 0) {
                // 因碰撞物体为墙壁，所以此处实例化弹孔预制体，生成节点并设置在贴合墙壁的位置
                let effect = instantiate(this.decalHitWall);
                // 将弹孔的位置设置在碰撞点沿着碰撞面的法线方向向外偏移 n 单位距离的位置，确保在碰撞体表面显示
                effect.setWorldPosition(result.hitPoint.add(result.hitNormal.clone().multiplyScalar(this.floatInfrontOfWall)));
                effect.setWorldRotation(quat);
                effect.parent = this.node.parent;
            }
            else if (result.collider.node.name.indexOf('Enemies') >= 0){
                // 因碰撞物体为敌人，所以此处实例化出血粒子预制体，生成节点并设置在贴合敌人中弹部位的位置
                let effect = instantiate(this.bloodEffect);
                effect.setWorldPosition(result.hitPoint.add(result.hitNormal.clone().multiplyScalar(this.floatInfrontOfWall)));
                // 将出血粒子的位置设置在碰撞点沿着碰撞面的法线方向向外偏移 n 单位距离的位置，确保在碰撞体表面显示。
                effect.setWorldRotation(quat);
                effect.parent = this.node.parent;
            }
        }

        //完成射线检测之后，游戏不再需要渲染子弹，所以销毁当前节点
        this.node.destroy();
    }

}
